package org.moda.functional.fp;

import java.util.function.BiFunction;
import java.util.function.Function;

public interface Monad<A> extends Applicative<A> {
    // (A, A => F[B]) => F[B]
    // 其实这里A就是this，实际上就是 (A => F[B]) => F[B]
    public <B> Monad<B> flatMap(Function<A, Monad<B>> f);

    /**
     * B => F[B]
     */
    public <B> Monad<B> unit(B b);

    @Override
    public default <B> Monad<B> map(Function<A, B> abf) {
        Function<A, Monad<B>> f = a -> this.unit(abf.apply(a));
        return this.flatMap(f);
    }

    @Override
    public default <B> Monad<B> apply(Applicative<Function<A, B>> fa) {
        // Monad<Function<? super A, ? extends B>, Mon> _fa = fa.<Monad<Function<? super A, ? extends B>, Mon>>convert();
        // Function<A, Monad<B, Mon>> xx = a -> fa.flatMap(x -> this.unit(x.apply(a)));
        // return this.flatMap(xx);
        Monad<Function<A, B>> _fa = fa.<Monad<Function<A, B>>>convert();
        Function<A, Monad<B>> f = a -> _fa.map(x -> x.apply(a));
        return this.flatMap(f);
    }
}
